﻿// -----------------------------------------------------------------------
// <copyright file="PushRequestDetailService.cs" company="Zen Design Corp">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace Zen.BlackBerry.Push.Request
{
	using System;
	using System.Collections.Generic;
	using System.Linq;
	using Zen.BlackBerry.Common;
	using Zen.BlackBerry.Pap;
	using Zen.BlackBerry.Pap.Parser;
	using Microsoft.Practices.Unity;

	/// <summary>
	/// Implementation of the <see cref="IPushRequestDetailService"/> interface.
	/// </summary>
	public class PushRequestDetailService : IPushRequestDetailService
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="PushRequestDetailService"/> class.
		/// </summary>
		public PushRequestDetailService()
		{
		}

		/// <summary>
		/// Gets or sets the repository.
		/// </summary>
		/// <value>The repository.</value>
		[Dependency]
		public IPushRequestDetailRepository Repository
		{
			get;
			set;
		}

		private void ValidateUpdate(PushRequestDetail detail)
		{
		}

		private void ValidateUpdate(ResultNotification result)
		{
		}

		private PushRequestDetail ConvertToPushRequestDetail(ResultNotification resultNotification)
		{
			PushRequestDetail pushRequestDetail =
				new PushRequestDetail
				{
					Id = resultNotification.PushId,
					Address = resultNotification.Address,
					MessageState = resultNotification.MessageState,
					StatusCode = resultNotification.Code,
					StatusDescription = resultNotification.Description,
					SenderName = resultNotification.SenderName,
					SenderAddress = resultNotification.SenderAddress
				};
			if (resultNotification.EventTime != null)
			{
				pushRequestDetail.CompletedDate = resultNotification.EventTime.Value;
			}
			else
			{
				pushRequestDetail.CompletedDate = DateTime.UtcNow;
			}

			return pushRequestDetail;
		}

		#region IPushRequestDetailService Members

		/// <summary>
		/// Adds the specified push request detail to the persistent store.
		/// </summary>
		/// <param name="pushRequestDetail">The push request detail.</param>
		public void AddPushRequestDetail(PushRequestDetail pushRequestDetail)
		{
			Repository.AddPushRequestDetail(pushRequestDetail);
		}

		/// <summary>
		/// Adds the specified push request details to the persistent store.
		/// </summary>
		/// <param name="pushRequestDetails">The push request details.</param>
		public void AddPushRequestDetails(IEnumerable<PushRequestDetail> pushRequestDetails)
		{
			Repository.AddPushRequestDetails(pushRequestDetails);
		}

		/// <summary>
		/// Finds all push request details by the specified created-date range.
		/// </summary>
		/// <param name="fromDate">From date.</param>
		/// <param name="toDate">To date.</param>
		/// <param name="startIndex">The start index.</param>
		/// <param name="endIndex">The end index.</param>
		/// <returns></returns>
		public IEnumerable<PushRequestDetail> FindByDateRange(DateTime fromDate, DateTime toDate, int startIndex, int endIndex)
		{
			return Repository.FindByDateRange(fromDate, toDate, startIndex, endIndex);
		}

		/// <summary>
		/// Finds all the push request details for the specific push request.
		/// </summary>
		/// <param name="id">The id.</param>
		/// <returns></returns>
		public IEnumerable<PushRequestDetail> FindById(string id)
		{
			return Repository.FindById(id);
		}

		/// <summary>
		/// Finds a push request detail by the specified push request and address.
		/// </summary>
		/// <param name="id">The id.</param>
		/// <param name="address">The address.</param>
		/// <returns></returns>
		public PushRequestDetail FindByIdAndAddress(string id, string address)
		{
			return Repository.FindByIdAndAddress(id, address);
		}

		/// <summary>
		/// Finds push request details by the specified push request and addresses.
		/// </summary>
		/// <param name="id">The id.</param>
		/// <param name="addresses">The addresses.</param>
		/// <returns></returns>
		public IEnumerable<PushRequestDetail> FindByIdAndAddresses(string id, IEnumerable<string> addresses)
		{
			return Repository.FindByIdAndAddresses(id, addresses);
		}

		/// <summary>
		/// Finds all the push request details for the specific push request
		/// and given states.
		/// </summary>
		/// <param name="id">The id.</param>
		/// <param name="states">The states.</param>
		/// <returns></returns>
		public IEnumerable<PushRequestDetail> FindByIdAndStates(string id, IEnumerable<MessageState> states)
		{
			return Repository.FindByIdAndStates(id, states);
		}

		/// <summary>
		/// Finds all the push request details with the given status code for
		/// a specific push request.
		/// </summary>
		/// <param name="id">The id.</param>
		/// <param name="statusCode">The status code.</param>
		/// <returns></returns>
		public IEnumerable<PushRequestDetail> FindByIdAndStatusCode(string id, StatusCode statusCode)
		{
			return Repository.FindByIdAndStatusCode(id, statusCode);
		}

		/// <summary>
		/// Finds push request details by the specified push request and
		/// subscriber ids.
		/// </summary>
		/// <param name="id">The id.</param>
		/// <param name="subscriberIds">The subscriber ids.</param>
		/// <returns></returns>
		public IEnumerable<PushRequestDetail> FindByIdAndSubscriberIds(string id, IEnumerable<string> subscriberIds)
		{
			return Repository.FindByIdAndSubscriberIds(id, subscriberIds);
		}

		/// <summary>
		/// Finds push ids and application ids for the specific push requests
		/// and given state.
		/// </summary>
		/// <param name="ids">The ids.</param>
		/// <param name="state">The state.</param>
		/// <returns></returns>
		public IEnumerable<PushIdAndApplicationId> FindByIdsAndState(IEnumerable<string> ids, MessageState state)
		{
			return Repository.FindByIdsAndState(ids, state);
		}

		/// <summary>
		/// Finds all the push request details by the specified status code.
		/// </summary>
		/// <param name="statusCode">The status code.</param>
		/// <param name="startIndex">The start index.</param>
		/// <param name="endIndex">The end index.</param>
		/// <returns></returns>
		public IEnumerable<PushRequestDetail> FindByStatusCode(StatusCode statusCode, int startIndex, int endIndex)
		{
			return Repository.FindByStatusCode(statusCode, startIndex, endIndex);
		}

		/// <summary>
		/// Finds all push requests that are incomplete for a specific
		/// subscriber id and push application.
		/// </summary>
		/// <param name="applicationId">The application id.</param>
		/// <param name="subscriberId">The subscriber id.</param>
		/// <returns></returns>
		public IEnumerable<PushRequestDetail> FindIncompleteByAppIdAndSubId(string applicationId, string subscriberId)
		{
			return Repository.FindIncompleteByAppIdAndSubId(applicationId, subscriberId);
		}

		/// <summary>
		/// Gets size of all push request details by the specified date range.
		/// </summary>
		/// <param name="fromDate">From date.</param>
		/// <param name="toDate">To date.</param>
		/// <returns></returns>
		public int GetSizeByDateRange(DateTime fromDate, DateTime toDate)
		{
			return Repository.GetSizeByDateRange(fromDate, toDate);
		}

		/// <summary>
		/// Updates the specified push request detail in the persistent store.
		/// </summary>
		/// <param name="pushRequestDetail">The push request detail.</param>
		public void UpdatePushRequestDetail(PushRequestDetail pushRequestDetail)
		{
			ValidateUpdate(pushRequestDetail);

			try
			{
				Repository.UpdatePushRequestDetail(pushRequestDetail);
			}
			catch (Exception exception)
			{
				throw new PushSDKException("Exception caught update request detail.", exception);
			}
		}

		/// <summary>
		/// Updates the push request detail based on the specified
		/// resultNotification.
		/// </summary>
		/// <param name="resultNotification">The result notification.</param>
		public void UpdatePushRequestDetail(ResultNotification resultNotification)
		{
			ValidateUpdate(resultNotification);

			PushRequestDetail pushRequestDetail = 
				ConvertToPushRequestDetail(resultNotification);
			if (pushRequestDetail.Address == "*")
			{
				List<ResultNotification> notifications = new List<ResultNotification>();
				notifications.Add(resultNotification);
				UpdatePushRequestDetails(notifications);
			}
			else
			{
				UpdatePushRequestDetail(pushRequestDetail);
			}
		}

		/// <summary>
		/// Updates the push request details based on the specified list of
		/// resultNotifications.
		/// </summary>
		/// <param name="resultNotifications">The result notifications.</param>
		public void UpdatePushRequestDetails(IEnumerable<ResultNotification> resultNotifications)
		{
			List<PushRequestDetail> detailsWithAddresses = new List<PushRequestDetail>();
			List<PushRequestDetail> detailsWithoutAddresses = new List<PushRequestDetail>();

			foreach (var result in resultNotifications)
			{
				ValidateUpdate(result);

				PushRequestDetail pushRequestDetail =
					ConvertToPushRequestDetail(result);
				if (pushRequestDetail.Address == "*")
				{
					detailsWithoutAddresses.Add(pushRequestDetail);
				}
				else
				{
					detailsWithAddresses.Add(pushRequestDetail);
				}
			}

			try
			{
				Repository.UpdatePushRequestDetails(detailsWithAddresses);
				Repository.UpdatePushRequestDetailsWithoutAddresses(detailsWithoutAddresses);
			}
			catch (Exception exception)
			{
				throw new PushSDKException("Exception caught update request details.", exception);
			}
		}

		#endregion
	}
}
